package baidu

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/swxctx/ghttp"
	"github.com/swxctx/xlog"
)

/**
对话相关api
接口文档：https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11
*/

// Client 百度API请求客户端
type Client struct {
	// 基础请求api
	baseUri string

	// 应用的API Key
	clientId string
	// 应用的Secret Key
	clientSecret string

	// access token
	accessToken string
	// 过期时间[存储的是过期时间节点的时间戳]
	expireIn int64

	// 是否调试模式[调试模式可以输出详细的信息]
	debug bool

	// 最大空消息数量
	maxEmptyMessageCount int
}

func NewClient(apiKey, secretKey string, debug ...bool)(*Client,error){
	client := &Client{
		clientId:             apiKey,
		clientSecret:         secretKey,
		baseUri:              "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/%s?access_token=%s",
		maxEmptyMessageCount: 300,
	}
	if len(debug) > 0 {
		client.debug = debug[0]
	}

	if client.debug {
		xlog.SetLevel("debug")
	}

	// 初始化获取token
	err := client.getAccessToken()
	if err != nil {
		return nil,err
	}
	return client,nil
}

func MustNewClient(apiKey, secretKey string, debug ...bool)(*Client,error){
	client,err := NewClient(apiKey, secretKey,debug...)
	if err != nil {
		return nil,err
	}
	return client,nil
}

// Chat 对话方法
func (c *Client) Chat(model string, chatRequest *ChatRequest) (*ChatResponse, error) {
	if err := c.getAccessToken(); err != nil {
		return nil, err
	}

	chatRequest.Stream = false

	// new request
	req := ghttp.Request{
		Url:       fmt.Sprintf(c.baseUri, model, c.accessToken),
		Method:    "POST",
		ShowDebug: c.debug,
		Body:      chatRequest,
	}

	// send request
	resp, err := req.Do()
	if err != nil {
		return nil, fmt.Errorf("baidu: Chat err, err is-> %v", err)
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("baidu: Chat http response code not 200, code is -> %d", resp.StatusCode)
	}
	defer resp.Body.Close()

	// read body
	respBs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("baidu: Chat read resp body err-> %v", err)
	}
	if c.debug {
		xlog.Debugf("baidu: chat resp-> %s", string(respBs))
	}

	// unmarshal data
	var (
		chatResp *ChatResponse
	)

	err = json.Unmarshal(respBs, &chatResp)
	if err != nil {
		return nil, fmt.Errorf("baidu: Chat data unmarshal err-> %v", err)
	}
	return chatResp, nil
}

// ChatStream 流式对话方法
func (c *Client) ChatStream(model string, chatRequest *ChatRequest) (*StreamReader, error) {
	if err := c.getAccessToken(); err != nil {
		return nil, err
	}

	chatRequest.Stream = true

	// new request
	req := ghttp.Request{
		Url:       fmt.Sprintf(c.baseUri, model, c.accessToken),
		Method:    "POST",
		ShowDebug: c.debug,
		Body:      chatRequest,
	}
	req.AddHeader("Connection", "keep-alive")

	// send request
	resp, err := req.Do()
	if err != nil {
		return nil, fmt.Errorf("baidu: ChatStream err, err is-> %v", err)
	}

	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return nil, fmt.Errorf("baidu: ChatStream http response code not 200, code is -> %d", resp.StatusCode)
	}

	// 交给外部调用逻辑处理
	return newStreamReader(resp, c.maxEmptyMessageCount), nil
}

// GetAccessToken 返回access token信息，比如在相同业务系统还需要用到这个Token
func (c *Client)GetAccessToken() (string, int64) {
	return c.accessToken, c.expireIn
}

// RefreshAccessToken 刷新access token
func (c *Client)RefreshAccessToken() error {
	return c.refreshAccessToken()
}

// SetMaxEmptyMessageCount 最大空消息数量
func (c *Client)SetMaxEmptyMessageCount(count int) {
	c.maxEmptyMessageCount = count
}

// SetDebug debug开关
func (c *Client)SetDebug(debug bool) {
	c.debug = debug
}